﻿using ChoiceTech.Halcon.Control;
using DevExpress.XtraEditors.Controls;
using HalconDotNet;
using MvCamCtrl.NET;
using MvCamCtrl.NET.CameraParams;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media.Media3D;

namespace HTHMachineVision
{
    public class CameraService
    {
        //相机对象
        public CCamera m_MyCamera = new CCamera();
        //相机信息集合
        public List<CCameraInfo> m_ltDeviceList = new List<CCameraInfo>();
        //连接状态
        public bool IsCollectionImage = false;
        
        //图像回调委托
        public cbOutputExdelegate ImageCallback;



        /// <summary>
        /// 查找设备
        /// </summary>
        public void DeviceListAcq(ComboBox cbDeviceList)
        {
            // ch:创建设备列表 
            //System.GC.Collect();//手动垃圾回收

            //清空设备下拉框列表
            cbDeviceList.Items.Clear();
            //清空相机信息列表
            m_ltDeviceList.Clear();
            // 查找相机设备  CSystem.MV_CAMERALINK_DEVICE采集卡
            int nRet = CSystem.EnumDevices(CSystem.MV_GIGE_DEVICE
                                         | CSystem.MV_USB_DEVICE, ref m_ltDeviceList);
            if (0 != nRet)
            {
                //方法执行失败的提示，不是找不到相机
                ShowErrorMsg("Enumerate devices fail!", 0);
                return;
            }

            // ch:在窗体列表中显示设备名 
            for (int i = 0; i < m_ltDeviceList.Count; i++)
            {
                //判断是否是GIGE（千兆网口协议）
                if (m_ltDeviceList[i].nTLayerType == CSystem.MV_GIGE_DEVICE)
                {
                    //转换成网口类型对象
                    CGigECameraInfo gigeInfo = (CGigECameraInfo)m_ltDeviceList[i];
                    //下拉框添加相机列表信息
                    // gigeInfo.chSerialNumber  相机序列号唯一
                    cbDeviceList.Items.Add("GEV: " + gigeInfo.chManufacturerName + " " + gigeInfo.chModelName + " (" + gigeInfo.chSerialNumber + ")");

                }
                else if (m_ltDeviceList[i].nTLayerType == CSystem.MV_USB_DEVICE)
                {
                    CUSBCameraInfo usbInfo = (CUSBCameraInfo)m_ltDeviceList[i];
                    cbDeviceList.Items.Add("U3V: " + usbInfo.chManufacturerName + " " + usbInfo.chModelName + " (" + usbInfo.chSerialNumber + ")");

                }
            }

            // ch:选择第一项 
            if (m_ltDeviceList.Count != 0)
            {
                cbDeviceList.SelectedIndex = 0;
            }
        }


        /// <summary>
        /// 提示错误信息
        /// </summary>
        /// <param name="csMessage">错误信息</param>
        /// <param name="nErrorNum">错误代码</param>
        public void ShowErrorMsg(string csMessage, int nErrorNum)
        {
            string errorMsg;
            if (nErrorNum == 0)
            {
                errorMsg = csMessage;
            }
            else
            {
                errorMsg = csMessage + ": Error =" + String.Format("{0:X}", nErrorNum);
            }

            switch (nErrorNum)
            {
                case CErrorDefine.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break;
                case CErrorDefine.MV_E_SUPPORT: errorMsg += " Not supported function "; break;
                case CErrorDefine.MV_E_BUFOVER: errorMsg += " Cache is full "; break;
                case CErrorDefine.MV_E_CALLORDER: errorMsg += " Function calling order error "; break;
                case CErrorDefine.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break;
                case CErrorDefine.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break;
                case CErrorDefine.MV_E_NODATA: errorMsg += " No data "; break;
                case CErrorDefine.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break;
                case CErrorDefine.MV_E_VERSION: errorMsg += " Version mismatches "; break;
                case CErrorDefine.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break;
                case CErrorDefine.MV_E_UNKNOW: errorMsg += " Unknown error "; break;
                case CErrorDefine.MV_E_GC_GENERIC: errorMsg += " General error "; break;
                case CErrorDefine.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break;
                case CErrorDefine.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break;
                case CErrorDefine.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break;
                case CErrorDefine.MV_E_NETER: errorMsg += " Network error "; break;
            }

            MessageBox.Show(errorMsg, "PROMPT");
        }



        /// <summary>
        /// 获取参数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void GetParam(string tbExposure, string tbGain)
        {
            CFloatValue pcFloatValue = new CFloatValue();

            int nRet = CErrorDefine.MV_OK;

            // 获取曝光时间
            nRet = m_MyCamera.GetFloatValue("ExposureTime", ref pcFloatValue);
            if (CErrorDefine.MV_OK == nRet)
            {
                // F1 保留一位小数
                tbExposure = pcFloatValue.CurValue.ToString("F1");
            }

            // 获取增益
            nRet = m_MyCamera.GetFloatValue("Gain", ref pcFloatValue);
            if (CErrorDefine.MV_OK == nRet)
            {
                tbGain = pcFloatValue.CurValue.ToString("F1");
            }
        }

        /// <summary>
        /// 设置参数
        /// !!!设置前需要关闭自动模式，我们要追求图像的稳定性
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void SetParam(string tbExposure, string tbGain)
        {
            try
            {
                float.Parse(tbExposure);
                float.Parse(tbGain);
            }
            catch
            {
                ShowErrorMsg("Please enter correct type!", 0);
                return;
            }

            //设置曝光前 自动曝光为关闭模式 0 -->> 关闭 1 -->> 打开
            m_MyCamera.SetEnumValue("ExposureAuto", 0);
            //设置曝光参数
            int nRet = m_MyCamera.SetFloatValue("ExposureTime", float.Parse(tbExposure));
            if (nRet != CErrorDefine.MV_OK)
            {
                ShowErrorMsg("Set Exposure Time Fail!", nRet);
            }
            //设置增益前 自动增益为关闭模式 0 -->> 关闭 1 -->> 打开
            m_MyCamera.SetEnumValue("GainAuto", 0);
            //设置增益 
            nRet = m_MyCamera.SetFloatValue("Gain", float.Parse(tbGain));
            if (nRet != CErrorDefine.MV_OK)
            {
                ShowErrorMsg("Set Gain Fail!", nRet);
            }

        }

        /// <summary>
        /// 拍照
        /// </summary>
        public void GetImage()
        {
            //打开触发模式
            m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
            //设置触发源为 7 软件触发
            m_MyCamera.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
            //软触发命令
            m_MyCamera.SetCommandValue("TriggerSoftware");

            // 确保相机已打开
            /*if (m_MyCamera == null)
            {
                Console.WriteLine("Camera is not open.");
            }

            // 设置触发模式为 ON
            int ret = m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
            if (ret != CErrorDefine.MV_OK)
            {
                Console.WriteLine("Failed to set TriggerMode to ON.");
                return;
            }

            // 设置触发源为 软件触发
            ret = m_MyCamera.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
            if (ret != CErrorDefine.MV_OK)
            {
                Console.WriteLine("Failed to set TriggerSource.");
                return;
            }

            // 触发一次
            ret = m_MyCamera.SetCommandValue("TriggerSoftware");
            if (ret != CErrorDefine.MV_OK)
            {
                Console.WriteLine("Failed to trigger software command.");
                return;
            }

            // 确保回调函数已经被设置
            if (ImageCallback == null)
            {
                Console.WriteLine("ImageCallback is not set.");
                return;
            }*/
        }

        /// <summary>
        /// 开始采集
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void StartGrab(bool bnContinuesMode,bool bnTriggerSoftware, string tbExposure, string tbGain)
        {
            //设置曝光、增益
            SetParam(tbExposure, tbGain);

            //设置触发模式

            //连续触发
            if (bnContinuesMode)
            {
                //关闭触发模式 -->> 自由采集
                m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
            }
            //软件触发
            else if (bnTriggerSoftware)
            {
                //打开触发模式
                m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
                //设置触发源为 7 软件触发
                m_MyCamera.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);

                //软触发命令
                m_MyCamera.SetCommandValue("TriggerSoftware");
            }
            //硬件触发
            else
            {
                //打开触发模式
                m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
                m_MyCamera.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
            }

        }



        /// <summary>
        /// 关闭相机
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void StopGrab()
        {
            // ch:停止采集 -->> 停止流
            m_MyCamera.StopGrabbing();
            //关闭设备
            m_MyCamera.CloseDevice();
            //释放句柄
            m_MyCamera.DestroyHandle();
        }


    }
}
